package com.novoda.runbuddy.service;

import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Formatter;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.TreeMap;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast;

import com.novoda.runbuddy.R;
import com.novoda.runbuddy.activity.Stopwatch;
import com.novoda.runbuddy.cannedroutes.CannedRunManagerImpl;
import com.novoda.runbuddy.controller.IRunController;
import com.novoda.runbuddy.controller.RunControllerImpl;
import com.novoda.runbuddy.model.Run;
import com.novoda.runbuddy.provider.ActivityID;
import com.novoda.runbuddy.util.DBHelperImpl;

public class RemoteStopClockService extends Service implements LocationListener{
	final RemoteCallbackList<IRemoteServiceCallback>	registeredCallbacks	= new RemoteCallbackList<IRemoteServiceCallback>();
	private NotificationManager							mNM;
	protected LocationManager							locationManager		= null;
	private static final String							TAG					= "[RBuddy]:" + "RemoteStopClockService";
	protected LocationProvider							provider;
	private boolean										clockRunning		= false;
	private IRunController 								runController;
	private long										startTime			= 0;
	private long										stopTime			= 0;
	private DBHelperImpl								dbHelper;
	// data related to replaying canned runs
	private boolean										cannedRunEnabled	= false;
	private CannedRunManagerImpl						cannedRunMgr;

	@Override
	public void onCreate() {

		mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

		Log.w(TAG, "Stopclock service created.");

		locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

		if (locationManager == null)
			Log.w(TAG, "null locationManager!");
		else
			Log.w(TAG, "got locationManager.");

		this.registerReceiver(intentReceiver, new IntentFilter(ActivityID.MY_LOCATION_CHANGED_ACTION));
		dbHelper = new DBHelperImpl(this);

		showNotification();

		cannedRunMgr = new CannedRunManagerImpl(this);
		runController = new RunControllerImpl();
	}

	private final BroadcastReceiver				intentReceiver	= new BroadcastReceiver() {

		@Override
		public void onReceive(Context context, Intent intent) {
			Location loc = (Location) intent.getParcelableExtra("location");

			Log.w(TAG, "Got Location Intent in Service " + loc.getLatitude() + ", " + loc.getLongitude());

			if (!cannedRunEnabled) {
				Message msg = Message.obtain(messageHandler, ActivityID.LOCATION_UPDATE, loc);
				messageHandler.sendMessageDelayed(msg, 50);
			}

		}

	};

	private final Handler	messageHandler	= new Handler() {

		@Override
		public void handleMessage(Message msg) {

			switch (msg.what) {
				case ActivityID.STARTSTOPCLOCK:
					Log.w(TAG, "Stopclock service received request to start 1.");
					messageHandler.sendEmptyMessage(ActivityID.UPDATESTOPCLOCK);
					locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0,	locationListener);
	
					break;
	
				case ActivityID.STOPSTOPCLOCK:
					Log.w(TAG, "Stopclock service received request to stop 1.");
					runController.stopRun(stopTime);
					break;
	
				case ActivityID.LOCATION_UPDATE:
					// Notify the client of the update
					final int registered = registeredCallbacks.beginBroadcast();
					Location loc = (Location) msg.obj;
					for (int i = 0; i < registered; i++) {
						try {
							registeredCallbacks.getBroadcastItem(i).updatedRoute(loc);
						} catch (RemoteException e) {
							Log.e(TAG, "Remote service recieved dead object.");
						}
					}
	
					registeredCallbacks.finishBroadcast();			
					
					if (runController.aRunIsCurrentlyActive()){
						Log.i(TAG, "Recieved request to add checkPoint on current Run. longitude=[" + loc.getLongitude() +"] latitude=[" + loc.getLatitude() + "] ");
						runController.addCheckPoint(loc);
					}
					
					break;
	
				default:
					super.handleMessage(msg);
				}
		}
	};

	/*
	 * IRemoteStopClockServiceInterface is defined through AIDL
	 */
	private final IRemoteStopClockService.Stub	messageBinder	= new IRemoteStopClockService.Stub() {
		public void registerStopClockUpdateListener(IRemoteServiceCallback cb) {
			if (cb != null) {
				registeredCallbacks.register(cb);
			}
		}

		public void unregisterStopClockUpdateListener( IRemoteServiceCallback cb) {
			if (cb != null) {
				registeredCallbacks.unregister(cb);
			}
		}

		public void terminateServiceIfIdle() {
			Log.w(TAG, "service received terminateIfIdle request.");
			// Give client a second to unbind interface. This prevents
			// exceptions when service disappears while client still
			// has a connection.
			new Thread() {
				public void run() {
					try {
						sleep(1000);
					} catch (InterruptedException e) {
						// don't
						// care
					}
					if (clockRunning == false) {
						Log.w(TAG,
								"Stopclock service terminating self.");
						RemoteStopClockService.this.stopSelf();
					}
				}
			}.start();
		}

		public void startStopClock(long startTime) {
			clockRunning = true;
			RemoteStopClockService.this.startTime = startTime;
			
			Calendar cal = Calendar.getInstance();
			cal.setTimeInMillis(System.currentTimeMillis());
			Format formatter = new SimpleDateFormat("EEEEddMMMyy");
			
			runController.startNewRun(dbHelper,	"Run" + formatter.format(cal.getTime()), startTime);
			
			startTrackingRoute();
		}

		public void stopStopClock(long stopTime) {
			clockRunning = false;
			// timerRunnerThread.stop();
			Log.i(TAG, "Received request to stop stopClock" );
			RemoteStopClockService.this.stopTime = stopTime;
			stopTrackingRoute();
			runController.stopRun(stopTime);
//			runController.addNewRunOnRoute();
		}

		public long getStartTime() {
			return startTime;
		}

		public long getStopTime() {
			return stopTime;
		}

		public boolean isStopClockRunning() {
			return clockRunning;
		}

		public void resetStopClock() {
		}

		public long getCurrentJogId() {
			
			if (runController.aRunIsCurrentlyActive()){
				Log.v(TAG, "Geting the current Jog ID:" + runController.getCurrentRunID());
				return runController.getCurrentRunID();
			}
			
			return 0;
		}

		public boolean getCannedRouteEnabled() {
			return cannedRunEnabled;
		}

		public int getCannedRouteId() {
			return cannedRunMgr.getRunId();
		}

		public double getCannedRouteSpeed() {
			return cannedRunMgr.getSpeed();
		}

		public void setCannedRouteEnabled(boolean enabled) {
			cannedRunEnabled = enabled;

		}

		public void setCannedRouteId(int id) {
			cannedRunMgr.setRunId(id);
		}

		public void setCannedRouteSpeed(double speed) {
			cannedRunMgr.setSpeed(speed);
		}

	};

	private LocationListener locationListener = new LocationListener()
	{

		public void onLocationChanged(Location loc) {
			Log.w(TAG, "Got locationListener in Service "	+ loc.getLatitude() + ", " + loc.getLongitude());

			if (!cannedRunEnabled) {
				Message msg = Message.obtain(messageHandler, ActivityID.LOCATION_UPDATE, loc);
				messageHandler.sendMessageDelayed(msg, 50);
			}
			
		}

		public void onProviderDisabled(String arg0) {
			
		}

		public void onProviderEnabled(String arg0) {
		}

		public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
		}
	
	};
	
	public void startTrackingRoute() {

		if (!cannedRunEnabled) {
			final long MINIMUM_DISTANCECHANGE_FOR_UPDATE = 25; // in Meters
			final long MINIMUM_TIME_BETWEEN_UPDATE = 5000; // in Milliseconds
			List<String> locProviders = locationManager.getAllProviders();
			
			Message msg = Message.obtain(messageHandler, ActivityID.STARTSTOPCLOCK, null);
			messageHandler.sendMessageDelayed(msg, 50);

			this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0,	locationListener);
		} else {
			cannedRunMgr.startRun(messageHandler);
		}
	}

	public void stopTrackingRoute() {
		if (!cannedRunEnabled) {
//			this.locationManager.removeUpdates(new Intent(ActivityID.MY_LOCATION_CHANGED_ACTION));
		} else {
			cannedRunMgr.stopRun();
		}
	}

	private void showNotification() {
		Intent contentIntent = new Intent(this, Stopwatch.class);
		Intent appIntent = new Intent(this, Stopwatch.class);
		CharSequence text = getText(R.string.local_service_started);

		//mNM.notify(R.string.local_service_started, new Notification(R.drawable.stat_sample, text, System.currentTimeMillis()));
	}

	@Override
	public IBinder onBind(Intent arg0) {
		return messageBinder;
	}

	@Override
	public void onDestroy() {
		//mNM.cancel(R.string.local_service_started);
		Toast.makeText(this, getText(R.string.local_service_stopped), Toast.LENGTH_SHORT).show();

		this.unregisterReceiver(intentReceiver);

		registeredCallbacks.kill();
		messageHandler.removeMessages(ActivityID.UPDATESTOPCLOCK);
	}

	public void onLocationChanged(Location arg0) {

	}

	public void onProviderDisabled(String arg0) {
		stopTrackingRoute();

	}

	public void onProviderEnabled(String arg0) {
		startTrackingRoute();
	}

	public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
		
	}

	
//	protected void saveJogLogEntry(String name, long startTime, long stopTime) {
//
//		TreeMap<Long, Location> locationsAndTimes = currentRoute.getlocationsAndTimes();
//		
//		dbHelper.addJogEntry(new Jog(name, name, locationsAndTimes)); 
//		
//	}


}
